using System;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Coderoom.ScrumPlanner.Data.Contracts;
using Coderoom.ScrumPlanner.Domain;
using Coderoom.ScrumPlanner.Utilities;

namespace Coderoom.ScrumPlanner.Data.Repositories.Xml
{
	public sealed class XmlTaskRepository : XmlRepository, ITaskRepository
	{
		public override string DataFileName
		{
			get { return "Tasks.xml"; }
		}

		#region ITaskRepository Members

		public TaskCollection GetTasks(Guid userStoryId)
		{
			Lock.EnterReadLock();

			try
			{
				var result = GetTasksInternal().Where(task => task.UserStoryId == userStoryId).ToArray();
				return new TaskCollection(result);
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public Task GetTask(Guid taskId)
		{
			Lock.EnterReadLock();

			try
			{
				return GetTasksInternal().Where(task => task.Id == taskId).SingleOrDefault();
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public void CreateTask(Task task)
		{
			Lock.EnterWriteLock();

			try
			{
				task.Id = Guid.NewGuid();

				var taskData = ReadXml();
				// ReSharper disable PossibleNullReferenceException
				taskData.Root.Add(new XElement("Task", new XAttribute("id", task.Id), new XAttribute("userStoryId", task.UserStoryId), new XElement("Title", task.Title), new XElement("Slug", task.Slug),
				                               new XElement("EstimatedComplexity", task.EstimatedComplexity)));
				// ReSharper restore PossibleNullReferenceException
				WriteXml(taskData);
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		public bool DeleteTask(Guid taskId)
		{
			Lock.EnterWriteLock();

			try
			{
				var taskData = ReadXml();

				var taskToDelete = taskData.ImmediateDescendants("Task").Where(task => task.ReadAttributeAsGuid("id") == taskId).SingleOrDefault();

				if (taskToDelete != null)
				{
					taskToDelete.Remove(); // removes it from parent
					WriteXml(taskData);
					return true;
				}

				return false;
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		#endregion

		private IQueryable<Task> GetTasksInternal()
		{
			var taskData = ReadXml();

			return (from task in taskData.ImmediateDescendants("Task")
			        select new Task
			        {
			        	Id = task.ReadAttributeAsGuid("id"),
			        	UserStoryId = task.ReadAttributeAsGuid("userStoryId"),
			        	Title = task.ReadChildValue("Title"),
			        	Slug = task.ReadChildValue("Slug"),
			        	EstimatedComplexity = Convert.ToByte(task.ReadChildValue("EstimatedComplexity"), CultureInfo.InvariantCulture)
			        }).AsQueryable();
		}
	}
}